#pragma once
#include "vec3.h"
#include <cmath>

mray::vec3::vec3(){
	x = y = z = a = 0.f;
}

mray::vec3::vec3(float x, float y, float z, float a){
	this->x = x;
	this->y = y;
	this->z = z;
	this->a = a;
}
 
mray::vec3 mray::vec3::operator + (const vec3& v)const{
	return vec3(x+v.x, y+v.y, z+v.z);
}

 
mray::vec3 mray::vec3::operator - (const vec3& v)const{
	return vec3(x-v.x, y-v.y, z-v.z);
}

mray::vec3 mray::vec3::operator * (float f)const{
	return vec3(x*f, y*f, z*f);
}

mray::vec3 mray::vec3::operator / (float f)const{
	float invf = 1.0f/f;
	return vec3(x*invf, y*invf, z*invf);
}

mray::vec3 mray::vec3::operator-(void) const{
	return vec3(-x, -y, -z);
}

mray::vec3& mray::vec3::operator += (const mray::vec3& v){
	x += v.x;
	y += v.y;
	z += v.z;
	return *this;
}

mray::vec3& mray::vec3::operator -= (const mray::vec3& v){
	x -= v.x;
	y -= v.y;
	z -= v.z;
	return *this;
}

mray::vec3& mray::vec3::operator *= (float f){
	x *= f;
	y *= f;
	z *= f;
	return *this;
}

mray::vec3& mray::vec3::operator /= (float f){
	float invf = 1.0f/f;
	x *= invf;
	y *= invf;
	z *= invf;
	return *this;
}

mray::vec3& mray::vec3::normalize(void){
	float f = sqrt(x*x + y*y + z*z);
	x /= f;
	y /= f;
	z /= f;
	return *this;
}

mray::vec3 mray::vec3::operator ^(const mray::vec3& v)const{
	return vec3(r*v.r, g*v.g, b*v.b);
}

mray::vec3& mray::vec3::operator^=(const vec3& v)
{
	r *= v.r;
	g *= v.g;
	b *= v.b;
	return *this;
}

float mray::vec3::operator * (const mray::vec3& v)const{
	return x*v.x + y*v.y + z*v.z;
}

 
mray::vec3 mray::vec3::operator % (const mray::vec3& v)const{
	return vec3(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x);
}

 
float mray::vec3::length()const{
	return sqrt(x*x + y*y + z*z);
}

float mray::vec3::LengthAndNorm()
{
	float f = std::sqrt(x*x + y*y + z*z);
	x /= f;
	y /= f;
	z /= f;
	return f;
}


float mray::vec3::dbl_length() const {
	return x*x + y*y + z*z;
}

mray::AXIS mray::vec3::GetMaxAbsAxis()const{
	float xx = abs(x);
	float yy = abs(y);
	float zz = abs(z);
	return xx>yy && xx>zz ? AXIS::X : yy>zz ? AXIS::Y : AXIS::Z;
}

mray::AXIS mray::vec3::GetMaxAxis() const
{
	return x>y && x>z ? AXIS::X : y>z ? AXIS::Y : AXIS::Z;
}

mray::AXIS mray::vec3::GetMinAbsAxis()const{
	float xx = abs(x);
	float yy = abs(y);
	float zz = abs(z);
	return xx<yy && xx<zz ? AXIS::X : yy<zz ? AXIS::Y : AXIS::Z;
}

mray::AXIS mray::vec3::GetMinAxis() const{
	return x<y && x<z ? AXIS::X : y<z ? AXIS::Y : AXIS::Z;
}

std::ostream& mray::operator << (std::ostream& os, const mray::vec3& v){
	os << v.x << ' ' << v.y << ' ' << v.z;
	return os;
}

float mray::vec3::GetXYZ()const{
	return x + y + z;
}